package com.qqt.csr.common.utils;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.exc.StreamReadException;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;

@Slf4j
@Component("snowflakeUtil")
public class SnowflakeUtil implements InitializingBean {
    private static volatile Snowflake snowflake;

    @Value("${server.port}")
    private String port;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Override
    public void afterPropertiesSet() throws Exception {
        InetAddress inetAddress = IPUtil.getInetAddress();
        long dataCenterId = getDatacenterId(inetAddress);

        String machineIdRedisKey = CacheKeyUtil.System.SNOWFLAKE_MACHINE_ID + ":" + inetAddress.getHostAddress() + "_" + port;
        Object mId = getRedisValue(machineIdRedisKey);
        long workerId = 0L;
        if (mId != null) {
            workerId = (Long) mId;
            snowflake = IdUtil.getSnowflake(workerId, dataCenterId);
        } else {
            workerId = redissonClient.getAtomicLong(String.format(CacheKeyUtil.System.SNOWFLAKE_DATA_CENTER_DISTRIBUTE, dataCenterId)).incrementAndGet();
            if (workerId > 31) {
                workerId = workerId % 32;
            }
            redissonClient.getBucket(machineIdRedisKey).set(workerId);
            snowflake = IdUtil.getSnowflake(workerId, dataCenterId);
        }

        DefaultIdentifierGenerator identifierGenerator = new DefaultIdentifierGenerator(workerId, dataCenterId);
        GlobalConfig globalConfig = GlobalConfigUtils.getGlobalConfig(sqlSessionFactory.getConfiguration());
        globalConfig.getSequence().setWorkerId(workerId);
        globalConfig.getSequence().setDatacenterId(dataCenterId);
        globalConfig.setIdentifierGenerator(identifierGenerator);

        IdWorker.setIdentifierGenerator(identifierGenerator);
    }

    public static Long nextId() {
        return snowflake.nextId();
    }

    public static String nextIdStr() {
        return nextId().toString();
    }

    private long getDatacenterId(InetAddress inetAddress) throws SocketException {
        long id = 0L;
        NetworkInterface network = NetworkInterface.getByInetAddress(inetAddress);
        byte[] mac = network.getHardwareAddress();
        if (null != mac) {
            id = ((0x000000FF & (long) mac[mac.length - 2]) | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6;
            id = id % 32;
        }

        return id;
    }

    private Object getRedisValue(String key){
        try {
            return redissonClient.getBucket(key).get();
        } catch (Exception e) {
            return null;
        }

    }
}
